module SearchTags
  include Radiant::Taggable

  desc %{    The namespace for all search tags.}
  tag 'search' do |tag|
    tag.expand
  end
  
  desc %{    Outputs <form> element of the search form.
    <r:search:form action="controller_url"[ ajax_results="element_id"[ ajax_delay="500"]][exclude_pages="/url/1/,/url/2/"]>
    
    action        - url to the page of type Search that will handle search request
    ajax_results  - if you want your form to be AJAX enabled, specify ID of element that will contain search results
    ajax_delay    - time of inactivity before search request submitted to the server
    exclude_pages - comma separated list of page URLs to exclude from results. Don't forget trailing slashes
    
    Any additional parameters will be added to the tag as attributes.
    If you use AJAX enabled form you can have separate page part for displaying AJAX results. It should be called `ajax_body'. 
    
    *Usage:*
<pre><code><r:search:form action="controller_url">
  <r:search:form:input />
  <input type="submit" />
  ...
</r:search:form></code></pre>
  }
  tag 'search:form' do |tag|
    unless action = tag.attr['action']
      raise StandardTags::TagError.new("`search:form' tag must contain `action' attribute")
    end
    result_id = tag.attr['ajax_results'] || nil
    ajax_delay = tag.attr['ajax_delay'] || 500
    exclude_pages = tag.attr['exclude_pages'] || ''
    int_attrs = ['ajax_results', 'ajax_delay', 'exclude_pages']
    output = %{<form method="get"} +
      tag.attr.delete_if {|key, value| int_attrs.include?(key)
        }.collect {|key, value| %{#{key}="#{value}"}}.join(" ") +
      %{>
        <input type="hidden" name="exclude_pages" value="#{exclude_pages}" />
        #{tag.expand}
      </form>}
    # if result_id not given, skip AJAX form init
    return output if result_id.nil?
    # otherwise init AJAX
    output << %{      <script type="text/javascript">
      var search_previous_value = '';
      var search_handler;
      Event.observe("q", "keyup", function(ev){
        clearTimeout(search_handler);
        search_form = Event.findElement(ev, 'form');
        search_handler = setTimeout(function(ev){
          if (this.getValue() == search_previous_value) { return; }
          search_previous_value = this.getValue();
          new Ajax.Updater("#{result_id}", search_form.action, {
            parameters: $(search_form).serialize(true),
            evalScripts: true,
            onLoading: function(){
              search_form.addClassName('loading');
            },
            onComplete: function(){
              search_form.removeClassName('loading');
              $("#{result_id}").show();
            }
          });
        }.bind(this, ev), #{ajax_delay});
      }.bindAsEventListener($('q')));
    </script>
    }
  end
  
  desc %{    Outputs input element for search form. All additional parameters will
    be added as tag attributes. However don't use type and name. ID attribute
    can be overwritten}
  tag 'search:form:input' do |tag|
    ["type", "name"].each do |attr|
      if tag.attr[attr]
        raise StandardTags::TagError.new("`search:form:input' tag can't contain `#{attr}' attribute")
      end
    end
    
    tag_id = tag.attr['id'] || "q"
    
    output = %{<input type="text" name="q" id="#{tag_id}" } + 
      tag.attr.delete_if {|attr, value| attr == 'id'
      }.collect {|key, value| %{#{key}="#{value}"}}.join(" ") +
      "/>"
  end
  
end
